/*
 * enc_shrm.c
 *
 *  Created on: 2018年10月16日
 *  Author: Degang.Wu (windragon@126.com)
 *  Desc:
 */

#include <semaphore.h>
#include <sys/shm.h>
#include "public.h"

//for share memory global variable
static int g_shrmid = -1;
static void* g_shrmpt = NULL;

sem_t* g_shrmsem = SEM_FAILED;
sem_t* g_devsem = SEM_FAILED;
sem_t* g_logsem = SEM_FAILED;

pENC_DEVSET_MASTER g_encset_mst = NULL;
pENC_DEVSET_SLAVE g_encset_slv = NULL;

char g_cfgpath[MAX_PATH] = {0};
int g_chlidx = -1;
int g_dump_chlidx = -1;

static int g_init_count = 0;

static const char* get_osd_typename(int type)
{
	if (type == BWENC_OSD_TYPE_LOGO)
	{
		return "logo";
	}
	else if (type == BWENC_OSD_TYPE_TEXT)
	{
		return "subtext";
	}
	else if (type == BWENC_OSD_TYPE_QRCODE)
	{
		return "qrcode";
	}

	return "unknow";
}
void shrmem_uninit(void)
{
	g_init_count--;
	if (g_init_count > 0)
	{
		return;
	}

	BW_INFO("bwenc====>shrmem_uninit\n");
	if (g_shrmpt != (void *) (-1) && g_shrmpt != NULL)
	{
		shmdt(g_shrmpt);
	}

	if (g_shrmsem != SEM_FAILED)
	{
		sem_close(g_shrmsem);
	}
	if (g_devsem != SEM_FAILED)
	{
		sem_close(g_devsem);
	}
	if (g_logsem != SEM_FAILED)
	{
		sem_close(g_logsem);
	}
	g_shrmpt = NULL;
	g_shrmid = -1;
	g_shrmsem = SEM_FAILED;
	g_devsem = SEM_FAILED;
	g_logsem = SEM_FAILED;
	g_encset_mst = NULL;
	g_encset_slv = NULL;
}

void enc_defaultPara_load()
{
	int i = 0;
	for(i = 0; i < ENC_TOTAL_CHLMAX; i++)
	{
		stENC_CHLSET& chlset = g_encset_mst->enc_chls[i];

		stENC_VIDSET& video = chlset.encchl_vid;
		video.vid_bitrate_kb = 1024;
		video.vid_bitrate_max = 1024;
		video.vid_bitrate_min = 1024;
		video.vid_fluctuate = 0;
		
		video.vid_codec = BWENC_VID_CODEC_H264;
		video.vid_dar = BWENC_VID_DAR_16_9;
		video.vid_fpsden = 1;
		video.vid_fpsnum = 25;
		video.vid_gopsize = 25;
		video.vid_width = 1920;
		video.vid_height = 1080;
		video.vid_level = 51;
		video.vid_profile = BWENC_VID_PROFILE_HIGH;
		video.vid_rctype = BWENC_VID_RC_CBR;

		stENC_AUDSET& audio = chlset.encchl_aud;
		audio.aud_bitrate_kb = 64;
		audio.aud_channle = 2;
		audio.aud_codec = BWENC_AUD_CODEC_AAC_HE;
		audio.aud_smp_fmt = BWENC_AUD_SMPFMT_S16;
		audio.aud_smp_rate = 48000;
		audio.aud_vol = 100;	

		stENC_TSSET &tsset = chlset.encchl_ts;
		snprintf((char*)tsset.ts_service_name, sizeof(tsset.ts_service_name), "%s-%d","bwsctv",i+1);
		snprintf((char*)tsset.ts_provider_name, sizeof(tsset.ts_provider_name), "%s", "WWW.BWSCTV.COM");
		tsset.ts_pmt_pid = 0x20;
		tsset.ts_service_id = 0x1;
		tsset.ts_pcr_pid = 0x21;
		tsset.ts_vid_pid = 0x21;
		tsset.ts_aud_pid = 0x22;
		tsset.ts_pcr_interval_ms = 0;
		tsset.ts_muxrate_kb = 2000; //
		
		//send to fpga;
		chlset.encchl_output.ethio_dipaddr = 0xEE000001; //238.0.0.1
		chlset.encchl_output.ethio_dipport = 60000 + i;	
	}
}

int shrmem_init(int isCreate)
{
	if (g_init_count++ > 0)
	{
		return 1;
	}

	g_shrmsem = sem_open(ENC_SHMINITSEM, O_CREAT, 0644, 1);
	if (g_shrmsem == SEM_FAILED)
	{
		BW_ERROR("bwenc====>shrmsem_open failed!\n");
		return 0;
	}

	g_devsem = sem_open(ENC_GDEVSEM, O_CREAT, 0644, 1);
	if (g_devsem == SEM_FAILED)
	{
		BW_ERROR("bwenc====>global devsem open failed!\n");
		shrmem_uninit();
		return 0;
	}

	g_logsem = sem_open(ENC_GLOGSEM, O_CREAT, 0644, 1);
	if (g_logsem == SEM_FAILED)
	{
		BW_ERROR("bwenc====>global logsem open failed!\n");
		shrmem_uninit();
		return 0;
	}

	if (enc_is_master())
	{
		g_shrmid = shmget((key_t) (ENC_SHRMEMKEY_M), sizeof(stENC_DEVSET_MASTER),
				0666 | IPC_CREAT);
	}
	else
	{
		g_shrmid = shmget((key_t) (ENC_SHRMEMKEY_S), sizeof(stENC_DEVSET_SLAVE),
				0666 | IPC_CREAT);
	}
	if (g_shrmid < 0)
	{
		BW_ERROR("bwenc====>can't create shared_mem!\n");
		shrmem_uninit();
		return 0;
	}

	g_shrmpt = shmat(g_shrmid, NULL, 0);
	if (g_shrmpt == (void *) (-1))
	{
		BW_ERROR("bwenc====>can't use shared_mem!\n");
		shrmem_uninit();
		return 0;
	}

	if (enc_is_master())
	{
		g_encset_mst = (pENC_DEVSET_MASTER) g_shrmpt;
	}
	else
	{
		g_encset_slv = (pENC_DEVSET_SLAVE) g_shrmpt;
	}

	if (isCreate)
	{
		shrmen_enc_eth_load();
	}

	sem_wait(g_shrmsem);
	if (enc_is_master())
	{
		if (g_encset_mst->enc_inited)
		{
			sem_post(g_shrmsem);
			BW_INFO("enc_inited, return\n");
			return 1;
		}
		else if (!isCreate)
		{
			sem_post(g_shrmsem);
			BW_ERROR(" uninit !!\n");
			shrmem_uninit();
			return 0;
		}

		BW_INFO("============>inited shrmem, memory size = %u bytes!<============\n",
				sizeof(stENC_DEVSET_MASTER));
		memset((void*) g_encset_mst, 0, sizeof(stENC_DEVSET_MASTER));

		//编码参数默认值；
		//enc_defaultPara_load();
		
		shrmem_enc_load();
	}
	else
	{
		if (g_encset_slv->enc_inited)
		{
			sem_post(g_shrmsem);
			BW_INFO("enc_inited, return\n");
			return 1;
		}
		else if (!isCreate)
		{
			sem_post(g_shrmsem);
			BW_ERROR(" uninit !!\n");
			shrmem_uninit();
			return 0;
		}

		BW_INFO("============>inited shrmem, memory size = %u bytes!<============\n",
				sizeof(stENC_DEVSET_SLAVE));
		memset((void*) g_encset_slv, 0, sizeof(stENC_DEVSET_SLAVE));
		shrmem_enc_load();
	}

	sem_post(g_shrmsem);

	return 1;
}

void  shrmem_enc_load()
{
	shrmen_enc_eth_load();

	if (enc_is_master())
	{
		shrmem_enc_load_mst(g_encset_mst);
		g_encset_mst->enc_ethdevnum = ENC_ETHIFMAX_MASTER;
		g_encset_mst->enc_appvsion = ENC_APP_MST_VER;
		g_encset_mst->enc_setvsion = 1;
		g_encset_mst->enc_savevsion = 0;
		g_encset_mst->enc_curvsion = 0;
		g_encset_mst->enc_inited = 1;
	}
	else
	{
		g_encset_slv->enc_ethdevnum = ENC_ETHIFMAX_SLAVE;
		g_encset_slv->enc_appvsion = END_APP_SLV_VER;
		g_encset_slv->enc_setvsion = 1;
		g_encset_slv->enc_savevsion = 0;
		g_encset_slv->enc_curvsion = 0;
		g_encset_slv->enc_inited = 1;
	}

}

static int dump_enc_ethio(pENC_ETHIOSET pethio)
{
	if (NULL == pethio)
	{
		return -1;
	}
	struct in_addr ipaddr;
	BW_INFO("\tethio.enable \t= %d\n", pethio->ethio_isenable);
	BW_INFO("\tethio.ethid \t= %d\n", pethio->ethio_ethid);
	ipaddr.s_addr = htonl(pethio->ethio_sipaddr);
	BW_INFO("\tethio.sip \t= %s(0x%x)\n", inet_ntoa(ipaddr), pethio->ethio_sipaddr);
	BW_INFO("\tethio.sport \t= %d\n", pethio->ethio_sipport);
	ipaddr.s_addr = htonl(pethio->ethio_dipaddr);
	BW_INFO("\tethio.dip \t= %s(0x%x)\n", inet_ntoa(ipaddr), pethio->ethio_dipaddr);
	BW_INFO("\tethio.dport \t= %d\n", pethio->ethio_dipport);
	BW_INFO("\tethio.bitrates \t= %d\n", pethio->ethio_bitrates);

	return 0;
}

static int dump_osd_set(pENC_OSDSET posd)
{
	if (NULL == posd)
	{
		return -1;
	}

	BW_INFO("\tosd.enable \t= %d\n", posd->osd_enable);
	if (!posd->osd_enable)
	{
		return 0;
	}

	BW_INFO("\tosd.type \t= %s\n", get_osd_typename(posd->osd_type));
	if (posd->osd_type == BWENC_OSD_TYPE_LOGO)
	{
		stENC_LOGOSET& logo = posd->osd_cfg.osd_logo;
		BW_INFO("\tlogo.num \t=%d\n", logo.logo_num);
		for (int i = 0; i < ENC_OSD_MAX_SLIDE_NUM; i++)
		{
			BW_INFO("\tlogo.url[%d] \t=%s\n", i, (char*)logo.logo_url[i]);
		}
		BW_INFO("\tlogo.opacity \t=%d\n", logo.logo_opacity);
		BW_INFO("\tlogo.width \t=%d\n", logo.logo_width);
		BW_INFO("\tlogo.height \t=%d\n", logo.logo_height);
		BW_INFO("\tlogo.x \t=%d\n", logo.logo_x);
		BW_INFO("\tlogo.y \t=%d\n", logo.logo_y);
		BW_INFO("\tlogo.movdir \t=%d\n", logo.logo_movdir);
		BW_INFO("\tlogo.movspeed \t=%d\n", logo.logo_movspeed);
	}
	else if (posd->osd_type == BWENC_OSD_TYPE_TEXT)
	{
		stENC_SUBSET& sub = posd->osd_cfg.osd_sub;
		BW_INFO("\tsub.content \t=%s\n", (char*)sub.sub_content);
		BW_INFO("\tsub.font \t=%s\n", (char*)sub.sub_font);
		BW_INFO("\tsub.fontsize \t=%d\n", sub.sub_fontsize);
		BW_INFO("\tsub.fontstyle \t=%d\n", sub.sub_fontstyle);
		
		BW_INFO("\tsub.fontcolor \t=%d\n", sub.sub_fontcolor);
		BW_INFO("\tsub.backcolor \t=%d\n", sub.sub_backcolor);
		BW_INFO("\tsub.x \t=%d\n", sub.sub_x);
		BW_INFO("\tsub.y \t=%d\n", sub.sub_y);
		BW_INFO("\tsub.width \t=%d\n", sub.sub_width);
		BW_INFO("\tsub.height \t=%d\n", sub.sub_height);
		
		BW_INFO("\tsub.movdir \t=%d\n", sub.sub_movdir);
		BW_INFO("\tsub.movspeed \t=%d\n", sub.sub_movspeed);
	}
	else if (posd->osd_type == BWENC_OSD_TYPE_QRCODE)
	{
		stENC_QRCODE& qr = posd->osd_cfg.osd_qr;
		BW_INFO("\tqr.url \t=%s\n", (char*)qr.qr_url);
		BW_INFO("\tqr.opacity \t=%d\n", qr.qr_opacity);
		BW_INFO("\tqr.width \t=%d\n", qr.qr_width);
		BW_INFO("\tqr.heiht \t=%d\n", qr.qr_height);
		BW_INFO("\tqr.x \t=%d\n", qr.qr_x);
		BW_INFO("\tqr.y \t=%d\n", qr.qr_y);
	}

	stENC_OSD_TMSET *p_tmset = NULL;
	BW_INFO("[period]");
	for(int i = 0; i < ENC_WEEK_DAYS; i++)
	{
		for(int j = 0; j < ENC_OSD_MAX_TM_NUM; j++)
		{
			p_tmset = &(posd->osd_effect_tm[i][j]);
			BW_INFO("\tday:%d,start time:%u,end time:%u",i,p_tmset->tm_start_sec,p_tmset->tm_end_sec);
		}
	}
	
	return 0;
}

static int  dump_enc_chl(pENC_CHLSET pchlset)
{
	if (NULL == pchlset)
	{
		return -1;
	}
	BW_INFO("\tencchl_setvsion \t= %d\n", pchlset->encchl_setvsion);
	BW_INFO("\tencchl_savevsion \t= %d\n", pchlset->encchl_savevsion);
	BW_INFO("\tencchl_curvsion \t= %d\n", pchlset->encchl_curvsion);
	BW_INFO("\tencchl_actcount \t= %d\n", pchlset->encchl_actcount);
	BW_INFO("\tencchl_procpid \t= %d\n", pchlset->encchl_procpid);
	BW_INFO("\tencchl_isrun \t= %d\n", pchlset->encchl_isrun);
	BW_INFO("\tencchl_reset_chl \t= %d\n", pchlset->encchl_reset_chl);
	BW_INFO("\tencchl_ismptssel \t= %d\n", pchlset->encchl_ismptssel);

	stENC_VIDSET& video = pchlset->encchl_vid;
	BW_INFO("\tvid.codec \t= %d\n", video.vid_codec);
	BW_INFO("\tvid.vid_profile \t= %d\n", video.vid_profile);
	BW_INFO("\tvid.vid_level \t= %d\n", video.vid_level);
	BW_INFO("\tvid.vid_rctype \t= %d\n", video.vid_rctype);
	BW_INFO("\tvid.vid_width \t= %d\n", video.vid_width);
	BW_INFO("\tvid.vid_height \t= %d\n", video.vid_height);
	BW_INFO("\tvid.vid_bitrate_kb \t= %d\n", video.vid_bitrate_kb);
	BW_INFO("\tvid.vid_bitrate_min \t= %d\n", video.vid_bitrate_min);
	BW_INFO("\tvid.vid_bitrate_max \t= %d\n", video.vid_bitrate_max);
	BW_INFO("\tvid.vid_gopsize \t= %d\n", video.vid_gopsize);
	BW_INFO("\tvid.vid_fpsnum \t= %d\n", video.vid_fpsnum);
	BW_INFO("\tvid.vid_fpsden \t= %d\n", video.vid_fpsden);
	BW_INFO("\tvid.vid_dar \t= %d\n", video.vid_dar);

	for (int i = 0; i < ENC_OSD_MAX_OVERLAY; i++)
	{
		BW_INFO("osd idx:%d\n", i);
		stENC_OSDSET& osd = pchlset->encchl_osd[i];
		dump_osd_set(&osd);
	}

	stENC_AUDSET& audio = pchlset->encchl_aud;
	BW_INFO("\taudio.aud_codec \t= %d\n", audio.aud_codec);
	BW_INFO("\taudio.aud_vol \t= %d\n", audio.aud_vol);
	BW_INFO("\taudio.aud_bitrate_kb \t= %d\n", audio.aud_bitrate_kb);
	BW_INFO("\taudio.aud_smp_rate \t= %d\n", audio.aud_smp_rate);
	BW_INFO("\taudio.aud_smp_fmt \t= %d\n", audio.aud_smp_fmt);
	BW_INFO("\taudio.aud_channle \t= %d\n", audio.aud_channle);

	stENC_TSSET& tsset = pchlset->encchl_ts;
	BW_INFO("\tts.service_name\t= %s\n", (char*)tsset.ts_service_name);
	BW_INFO("\tts.provider_name\t= %s\n", (char*)tsset.ts_provider_name);
	//BW_INFO("\tts.pmt_pid\t= 0x%x\n", tsset.ts_pmt_pid);
	BW_INFO("\tts.service_id\t= 0x%x\n", tsset.ts_service_id);
	BW_INFO("\tts.pmt_pid\t= 0x%x\n", tsset.ts_pmt_pid);
	BW_INFO("\tts.pcr_pid\t= 0x%x\n", tsset.ts_pcr_pid);
	BW_INFO("\tts.video_pid\t= 0x%x\n", tsset.ts_vid_pid);
	BW_INFO("\tts.audio_pid\t= 0x%x\n", tsset.ts_aud_pid);
	BW_INFO("\tts.pcr_interval\t= %dms\n", tsset.ts_pcr_interval_ms);
	BW_INFO("\tts.bitrate\t= %dkb\n", tsset.ts_muxrate_kb);

	stENC_ETHIOSET& ethio = pchlset->encchl_output;
	dump_enc_ethio(&ethio);
	return 0;
}

static int   shrmem_dump_mst(int argc, char**argv)
{
	uint i = 0;
	int ii = 0;

	BW_INFO("============>bwenc dump(master) start...!\n");

	if(shrmem_init(0)==0)
	{
		return -1;
	}
	BW_INFO("========================>BWENCSET SETTING DUMP<========================\n");
	BW_INFO("enc_inited = %d\n",g_encset_mst->enc_inited);
	BW_INFO("enc_appvsion = %d\n",g_encset_mst->enc_appvsion);

	BW_INFO("enc_setvsion = %d\n",g_encset_mst->enc_setvsion);
	BW_INFO("enc_savevsion = %d\n",g_encset_mst->enc_savevsion);
	BW_INFO("enc_curvsion = %d\n",g_encset_mst->enc_curvsion);

	BW_INFO("enc_ethdevnum = %d\n",g_encset_mst->enc_ethdevnum);
	for (i = 0; i < g_encset_mst->enc_ethdevnum; i++)
	{
		BW_INFO("ethid[%d].enc_ethdevname = %s\n", i, g_encset_mst->enc_ethdevname[i]);
		for (ii = 0; ii < ENC_ETHIPMAX; ii++)
		{
		    BW_INFO("ethid[%d].enc_ethdevipaddr%d = %d.%d.%d.%d\n",i,ii,
		    		(g_encset_mst->enc_ethdevipaddr[i][ii]>>24)&0xff,
		    		(g_encset_mst->enc_ethdevipaddr[i][ii]>>16)&0xff,
		    		(g_encset_mst->enc_ethdevipaddr[i][ii]>>8)&0xff,
		    		 g_encset_mst->enc_ethdevipaddr[i][ii]&0xff);
		}
	}

	for (int i = 0; i < ENC_MAX_SUB_BOARD; i++)
	{
		BW_INFO("sboard[%d] regflag=%d",i, g_encset_mst->sboard[i].reg_flag);
		BW_INFO("sboard[%d] status=%d", i, g_encset_mst->sboard[i].status);
	}

	if (g_dump_chlidx >= 0 && g_dump_chlidx < ENC_TOTAL_CHLMAX)
	{
		BW_INFO("========enc channel idx[%d]=====\n", g_dump_chlidx);
		dump_enc_chl(&g_encset_mst->enc_chls[g_dump_chlidx]);
	}
	else
	{
		for (i = 0; i < ENC_TOTAL_CHLMAX; i++)
		{
			BW_INFO("========enc channel idx[%d]=====\n", i);
			dump_enc_chl(&g_encset_mst->enc_chls[i]);
		}
	}

	shrmem_uninit();
	return 0;
}

static int   shrmem_dump_slv(int argc, char**argv)
{
	uint i = 0;
	int ii = 0;
	if(shrmem_init(0)==0)
	{
		return -1;
	}

	BW_INFO("============>bwenc dump(slave) start...!\n");

	BW_INFO("========================>BWENCSET SETTING DUMP<========================\n");
	BW_INFO("enc_inited = %d\n",g_encset_slv->enc_inited);
	BW_INFO("enc_appvsion = %d\n",g_encset_slv->enc_appvsion);

	BW_INFO("enc_setvsion = %d\n",g_encset_slv->enc_setvsion);
	BW_INFO("enc_savevsion = %d\n",g_encset_slv->enc_savevsion);
	BW_INFO("enc_curvsion = %d\n",g_encset_slv->enc_curvsion);

	BW_INFO("enc_ethdevnum = %d\n",g_encset_slv->enc_ethdevnum);
	for(i=0;i<g_encset_slv->enc_ethdevnum;i++)
	{
		BW_INFO("ethid[%d].enc_ethdevname = %s\n",i,g_encset_slv->enc_ethdevname[i]);
		for (ii = 0; ii < ENC_ETHIPMAX; ii++)
		{
		    BW_INFO("ethid[%d].enc_ethdevipaddr%d = %d.%d.%d.%d\n",i,ii,(g_encset_slv->enc_ethdevipaddr[i][ii]>>24)&0xff,(g_encset_slv->enc_ethdevipaddr[i][ii]>>16)&0xff,(g_encset_slv->enc_ethdevipaddr[i][ii]>>8)&0xff,g_encset_slv->enc_ethdevipaddr[i][ii]&0xff);
		}
	}

	if (g_dump_chlidx >= 0 && g_dump_chlidx < ENC_MAX_CHL)
	{
		BW_INFO("========enc channel idx[%d]=====\n", g_dump_chlidx);
		dump_enc_chl(&g_encset_slv->enc_chls[g_dump_chlidx]);
	}
	else
	{
		for (i = 0; i < ENC_MAX_CHL; i++)
		{
			BW_INFO("========enc channel idx[%d]=====\n", i);
			dump_enc_chl(&g_encset_slv->enc_chls[i]);
		}
	}
	shrmem_uninit();
	return 0;
}

int   shrmem_dump(int argc, char**argv)
{
	if (enc_is_master())
	{
		return shrmem_dump_mst(argc, argv);
	}
	else
	{
		return shrmem_dump_slv(argc, argv);
	}

}

/*
 *	0 --> priv (communicate between slave and master)
 *	1 --> manager
 *	2 --> data input
 *	3 --> data output
 *	4 --> fpga network(connect to internal switch)
 */
const char* g_ethname_mst[ENC_ETHIFMAX_MASTER] = {
		"eth0", "eth1", "eth2", "eth3", "eth4"
};

const char* g_ethname_slv[ENC_ETHIFMAX_SLAVE] = {
		"eth0"
};

void  shrmen_enc_eth_load()
{
	U16	i = 0;
	if (enc_is_master())
	{
		if (g_encset_mst == NULL)
		{
			return;
		}
		for (i = 0; i < ENC_ETHIFMAX_MASTER; i++)
		{
			snprintf(BW_CHAR g_encset_mst->enc_ethdevname[i], sizeof(g_encset_mst->enc_ethdevname[i]), "%s", g_ethname_mst[i]);
		}

	}
	else
	{
		if (g_encset_slv == NULL)
		{
			return;
		}
		for (i = 0; i < ENC_ETHIFMAX_SLAVE; i++)
		{
			snprintf(BW_CHAR g_encset_slv->enc_ethdevname[i], sizeof(g_encset_slv->enc_ethdevname[i]), "%s", g_ethname_slv[i]);
		}
	}
}
